Introduction

Our group would like to study employee attrition using the Employee Attrition dataset from Kaggle. As there is potentially identifying information about individuals, this dataset is a fictional dataset created by IBM data scientists to protect the privacy, while simulating real employee information in a typical biomedical company.

In the job market, it is relatively rare for an individual to stay forever in one company for the entire career life. Oftentimes, people move on to a different company, hopefully for better income or treatment potentials; people might have to switch jobs due to family reasons and change of address; in some situations, employees might be forced to leave, either due to company restructuring and layoffs, or just poor individual job performance. Employee attrition could refer to any of the above circumstances and many more, when an employee leaves the company they work for for any reason, both voluntarily or involuntarily.

Employee attrition, of course, is normal. Certain employee attrition is inevitable–retirement, illness, laying off, etc; but many other types are manageable–the company can always attract employees by making their work enjoyable for them. It is highly important for human resources to keep track of employee attrition statistics, especially in positions where work experience and training is essential. If companies have a high attrition proportion, it might signal poor income potential, poor working environment, or the companies’ poor future prospects; and it could often lead to problems such as gap in worker training and discontinuity, which might lead to greater attrition, creating a vicious cycle. Thus, a well-functioning company should consciously keep track of its employee attrition statistics, and seek remedy when attrition statistics seem to go out of control.

Brief Intro to Data

Our Kaggle dataset contains the information of 1470 employees with 35 variables. The variables include employees’ demographic variables (binary gender, age, education, marriage status, etc.), career information (job role, job involvement, department, working years, salary, etc.), job satisfaction measure (work-life balance, job/relationship/environment satisfaction), performance rating, and other miscellaneous information. Unfortunately, there is no such variable that informs if the attrition is voluntary or involuntary. However, we could still gather a good amount of information and explore what are the potential factors behind attrition. Given that this is a fictional dataset referring to no specific companies, we will not make any judgements on whether one statistics is too high or one aspect is abnormal; we simply aim to explore potential causes and correlation with attrition status.

Analysis

1. Employee Demographics

Age

We first wish to explore the age distribution of employees, and in particular, the age differential between those who have left the job and those who haven’t.

Age distribution of employees. Combination of three plots: the plot of the left includes all employees, the plot on the top right includes those with attrition=YES, the plot on the bottom right includes those with attrition=NO

As shown above, the age range of employees spans widely, all the way from 18 to 60 years old, and the distribution is roughly bell shaped but somewhat right-skewed, with those who age between 25-40 being the major workforce. Overall, we see that those who have left the company tend to be younger than those who haven’t with more left-skewness in the age distribution, which is to be expected as younger people with fewer work experiences tend to seek more potentials by switching jobs, though we find that such difference isn’t quite large. In addition, we also find noticeable spikes in age with roughly similar intervals in between. Given the data sample size isn’t quite small, we can suspect that there might be certain recruitment reasons on the companies side other than total randomness. One possible reason is that the company might be actively seeking college graduates every other year, which might explain the roughly similarly-spaced spikes.

Following the line, it is not surprising that it shows a similar pattern when dividing the employees by departments in general. Nevertheless, there are some differences among departments. For Sales, both lines for attrited and not-attrited follow the same progression across age, indicating that attrition mainly follows the change of employee size in the company. Though we are restricted to the small data size for the human resources department, we can tell that age is a more important factor than employee size in describing employee attrition. For the research and development department, we can inspect in two parts. The first part– age 18 to age around 32– both lines progress in a very similar way. In contrast, the two lines start to diverge around age 32: non-attrition increases and decreases while attrition decreases and then remains at a relatively small size of people. One possible explanation is that research and development requires a lot of pre-effort before actually gaining some response. Meaning the time before it is just sunk cost. Thus, some might prefer to stop loss in time by starting a new career when they still have a chance while some others prefer to stay in the field.

Gender

mosaic plot of attrition(y) vs gender(x)

In general, the employee attrition rate is about 16%, and we cannot discern an obvious distinction of attrition rate between male and females. We can, however, notice that the company generally employs more males than females. To get a sense of gender distribution across departments, we also draw the mosaic plot below. We find that males have the highest proportion in the Human Resource department, though there is also considerable disparity in the other two departments.

mosaic plot of department(x) vs gender(y)

Attrition vs. years at company

To get a sense of typically how long an employee stays in a company, I draw a Kaplan-Meier survival curve of employees, as shown in the graph below.

Kaplan-Meier survival curve for employee staying within the company. x axis stands for years in company, and yxis stands for the probability that the employee still stays at the company

The x-axis stands for years at a company for an individual, and the y-axis stands for the proportion of employees that still stays at the company, or the “survival” rate of employees. Mathematically, we could represent it as \(P(Survival)=1-P({Attrition})\) From the curve, we find that about half of all employees leave the company within 5 years, and only 20% of all employees will stay within the company for ten years.

2. Relationship between attrition and Income

One big factor that an employee quits the company is that they are not satisfied with their income and seek to find other jobs with higher income prospects. For this reason, we wish to explore the overall income status of employees. Note: as the Kaggle dataset did not provide the currency unit for income, we will also not include units for income in our analysis.

The monthly income distributions in the dataset using a density plot with the brown line showing the mean monthly income for all workers

The above histogram describes the overall income distribution by attrition status, with the smoothed green density. Overall, we observe a good amount of income disparity–the skewed distribution shows that most workers receive a monthly income lower than the average, while a few people receive a monthly income far higher than the average income in this company. In addition, we find that the income disparity seems more extreme within the attrited employees with much greater skewness and greater percentage earning less than 5,000 a month, and very small percentage of employees earning over 10,000 left the company. This provides certain evidence that income prospects are quite related with attrition status.

The monthly income distributions by three departments and gender using a box plot with the blue line showing the mean monthly income by department

We then take a step further into the monthly income distribution by department and attrition status. The boxplots above show that, among the three departments, human resources and research & development departments tend to have greater income inequality as we see relatively larger gaps between the median and the average income (shown by the dark brown line). At the same time, it seems that in these two departments, non-attrited employees tend to have much higher monthly income than those who left the company. Income inequality and attrition/non-attrition differential is less extreme for the sales department, but the lower-interquartile difference is still substantial. Overall, the sales department has the highest average monthly income 6959.2, the human resources department has the second highest average monthly income 6654.5, and the research & development department has the lowest average monthly income 6281.3.

In addition to the current income status, probably even more, employees care about how likely their income would increase in the future. We thus draw the scatter plot below to show the relationship between average monthly income and years at company. If we ignore the outliers who left the company after over 30 years serving for the company, we find that the prospect of pay raise is roughly the same between those both attrition groups, as we see a roughly parallel trend.

Average monthly income vs. Years at company

We look more closely at the percent salary hike by department in the group of boxplots below. The results corroborate the previous graph. Other than the human resources department which have the fewest employees, in both R&D and Sales departments, the income prospects for those who have and haven’t left the company is approximately the same, with very similar median, mean, and interquartile salary hike percentage. Thus, from this data, we don’t think future income prospects play as huge a role in attrition status as the current income.

Percent Salary Hike by Department and Attrition

3. Relationship between Job Satisfaction and Attrition

Probably even more important than income, employees’ overall job satisfaction ratings could potentially tell more about whether they are happy with their job. We thus also wish to explore the relationship between attrition and job satisfaction. In our dataset, job rating has four levels: 1 meaning “low,” 2 meaning “medium,” 3 meaning “high,” 4 meaning “very high.”

When looking at job satisfaction, it is unsurprising that the employees who rated “1” would more tend to leave the company in general. In addition, for the human resources department, half of the employees rated “1” attrited. However, it is interesting to note that there are even less employees attrited with rating “2” than other two higher ratings. Moreover, for the other two departments, although the attrition decreases with the increase of rating, the attrition differences among different ratings are not explicit. Thus, job satisfaction might not be a very informative influence when evaluating the attrition. Some possible explanations might be that employees’ rating might vary over time or some might not treat the rating seriously enough to respond with a valid value.

#Conclusion

Employee attrition is an important piece of information to keep track of for any large company, as it deeply concerns employees’ morale, work environment, and production continuity of the organization. In our Kaggle dataset, overall, we find that employee attrition appears to have the greatest correlation with income levels, while future income prospects and job satisfaction ratings seem less important factors. This has been informative for us and especially for human resources to understand the general trend and explanatory factors of employee attrition.

However, we also admittedly face limitations with our dataset. First, while we appreciate that the fictional dataset protects individual privacy, as we cannot identify any specific company, we don’t know how typical our data is and if the data can well represent all similar biomedical companies. Second, since we cannot track whether attrition is voluntary or not, we face restrictions in drawing more meaningful conclusions from our data. If we were able to locate the data more specifically at voluntary attrition, we might be able to more closely identify potential reasons from the companies’ side for employees quitting. Finally, given that our dataset, while reasonably large enough for us to make visual representations, does not contain quite many attrited data points(about over 200), and contains only three departments (Sales, R&D, Human resources), we couldn’t reasonably include all or as many variables as we desire, as that would leave too few data points in each group.

LS0tDQp0aXRsZTogIlNUQVQxMTIgUHJvamVjdC0tRW1wbG95ZWUgQXR0cml0aW9uIg0KYXV0aG9yOiAiSmVubnkgTGksIEdldmVuIExpdSwgV2VueHVhbiBaaHUiDQpkYXRlOiAnMjAyMi0wNC0xNicNCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgdGhlbWU6IHNpbXBsZXgNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IEZBTFNFLCBlcnJvcj1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFKQ0KYGBgDQoNCmBgYHtyIGxpYnJhcmllcyxtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShnZ21vc2FpYykNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShnZ3RoZW1lcykgDQpsaWJyYXJ5KGdlb2ZhY2V0KQ0KbGlicmFyeShvcGVuaW50cm8pDQpsaWJyYXJ5KGdwbG90cykNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeShnZ3RoZW1lcykgICAgIA0KbGlicmFyeShwbG90bHkpIA0KbGlicmFyeShnZ2FuaW1hdGUpDQpsaWJyYXJ5KGdpZnNraSkgDQpsaWJyYXJ5KHRyYW5zZm9ybXIpIA0KbGlicmFyeShwYXRjaHdvcmspIA0KbGlicmFyeShzdXJ2aXZhbCkNCmxpYnJhcnkoc2YpICAgICAgICAgIA0KbGlicmFyeShnZ3RoZW1lcykgICAgICANCmxpYnJhcnkoZ2dhbmltYXRlKSAgICAgDQpsaWJyYXJ5KHRyYW5zZm9ybXIpICAgIA0KbGlicmFyeShnaWZza2kpICAgICAgICANCmxpYnJhcnkocmVhZHIpDQp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQ0KYGBgDQoNCiMgSW50cm9kdWN0aW9uIA0KDQo+T3VyIGdyb3VwIHdvdWxkIGxpa2UgdG8gc3R1ZHkgZW1wbG95ZWUgYXR0cml0aW9uIHVzaW5nIHRoZSBbRW1wbG95ZWUgQXR0cml0aW9uIGRhdGFzZXRdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvcGF2YW5zdWJoYXNodC9pYm0taHItYW5hbHl0aWNzLWF0dHJpdGlvbi1kYXRhc2V0KSBmcm9tIEthZ2dsZS4gQXMgdGhlcmUgaXMgcG90ZW50aWFsbHkgaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24gYWJvdXQgaW5kaXZpZHVhbHMsIHRoaXMgZGF0YXNldCBpcyBhIGZpY3Rpb25hbCBkYXRhc2V0IGNyZWF0ZWQgYnkgSUJNIGRhdGEgc2NpZW50aXN0cyB0byBwcm90ZWN0IHRoZSBwcml2YWN5LCB3aGlsZSBzaW11bGF0aW5nIHJlYWwgZW1wbG95ZWUgaW5mb3JtYXRpb24gaW4gYSB0eXBpY2FsIGJpb21lZGljYWwgY29tcGFueS4NCg0KPkluIHRoZSBqb2IgbWFya2V0LCBpdCBpcyByZWxhdGl2ZWx5IHJhcmUgZm9yIGFuIGluZGl2aWR1YWwgdG8gc3RheSBmb3JldmVyIGluIG9uZSBjb21wYW55IGZvciB0aGUgZW50aXJlIGNhcmVlciBsaWZlLiBPZnRlbnRpbWVzLCBwZW9wbGUgbW92ZSBvbiB0byBhIGRpZmZlcmVudCBjb21wYW55LCBob3BlZnVsbHkgZm9yIGJldHRlciBpbmNvbWUgb3IgdHJlYXRtZW50IHBvdGVudGlhbHM7IHBlb3BsZSBtaWdodCBoYXZlIHRvIHN3aXRjaCBqb2JzIGR1ZSB0byBmYW1pbHkgcmVhc29ucyBhbmQgY2hhbmdlIG9mIGFkZHJlc3M7IGluIHNvbWUgc2l0dWF0aW9ucywgZW1wbG95ZWVzIG1pZ2h0IGJlIGZvcmNlZCB0byBsZWF2ZSwgZWl0aGVyIGR1ZSB0byBjb21wYW55IHJlc3RydWN0dXJpbmcgYW5kIGxheW9mZnMsIG9yIGp1c3QgcG9vciBpbmRpdmlkdWFsIGpvYiBwZXJmb3JtYW5jZS4gRW1wbG95ZWUgYXR0cml0aW9uIGNvdWxkIHJlZmVyIHRvIGFueSBvZiB0aGUgYWJvdmUgY2lyY3Vtc3RhbmNlcyBhbmQgbWFueSBtb3JlLCB3aGVuIGFuIGVtcGxveWVlIGxlYXZlcyB0aGUgY29tcGFueSB0aGV5IHdvcmsgZm9yIGZvciBhbnkgcmVhc29uLCBib3RoIHZvbHVudGFyaWx5IG9yIGludm9sdW50YXJpbHkuDQoNCj5FbXBsb3llZSBhdHRyaXRpb24sIG9mIGNvdXJzZSwgaXMgbm9ybWFsLiBDZXJ0YWluIGVtcGxveWVlIGF0dHJpdGlvbiBpcyBpbmV2aXRhYmxlLS1yZXRpcmVtZW50LCBpbGxuZXNzLCBsYXlpbmcgb2ZmLCBldGM7IGJ1dCBtYW55IG90aGVyIHR5cGVzIGFyZSBtYW5hZ2VhYmxlLS10aGUgY29tcGFueSBjYW4gYWx3YXlzIGF0dHJhY3QgZW1wbG95ZWVzIGJ5IG1ha2luZyB0aGVpciB3b3JrIGVuam95YWJsZSBmb3IgdGhlbS4gSXQgaXMgaGlnaGx5IGltcG9ydGFudCBmb3IgaHVtYW4gcmVzb3VyY2VzIHRvIGtlZXAgdHJhY2sgb2YgZW1wbG95ZWUgYXR0cml0aW9uIHN0YXRpc3RpY3MsIGVzcGVjaWFsbHkgaW4gcG9zaXRpb25zIHdoZXJlIHdvcmsgZXhwZXJpZW5jZSBhbmQgdHJhaW5pbmcgaXMgZXNzZW50aWFsLiBJZiBjb21wYW5pZXMgaGF2ZSBhIGhpZ2ggYXR0cml0aW9uIHByb3BvcnRpb24sIGl0IG1pZ2h0IHNpZ25hbCBwb29yIGluY29tZSBwb3RlbnRpYWwsIHBvb3Igd29ya2luZyBlbnZpcm9ubWVudCwgb3IgdGhlIGNvbXBhbmllcycgcG9vciBmdXR1cmUgcHJvc3BlY3RzOyBhbmQgaXQgY291bGQgb2Z0ZW4gbGVhZCB0byBwcm9ibGVtcyBzdWNoIGFzIGdhcCBpbiB3b3JrZXIgdHJhaW5pbmcgYW5kIGRpc2NvbnRpbnVpdHksIHdoaWNoIG1pZ2h0IGxlYWQgdG8gZ3JlYXRlciBhdHRyaXRpb24sIGNyZWF0aW5nIGEgdmljaW91cyBjeWNsZS4gVGh1cywgYSB3ZWxsLWZ1bmN0aW9uaW5nIGNvbXBhbnkgc2hvdWxkIGNvbnNjaW91c2x5IGtlZXAgdHJhY2sgb2YgaXRzIGVtcGxveWVlIGF0dHJpdGlvbiBzdGF0aXN0aWNzLCBhbmQgc2VlayByZW1lZHkgd2hlbiBhdHRyaXRpb24gc3RhdGlzdGljcyBzZWVtIHRvIGdvIG91dCBvZiBjb250cm9sLg0KDQojIyBCcmllZiBJbnRybyB0byBEYXRhDQo+T3VyIEthZ2dsZSBkYXRhc2V0IGNvbnRhaW5zIHRoZSBpbmZvcm1hdGlvbiBvZiAxNDcwIGVtcGxveWVlcyB3aXRoIDM1IHZhcmlhYmxlcy4gVGhlIHZhcmlhYmxlcyBpbmNsdWRlIGVtcGxveWVlcycgZGVtb2dyYXBoaWMgdmFyaWFibGVzIChiaW5hcnkgZ2VuZGVyLCBhZ2UsIGVkdWNhdGlvbiwgbWFycmlhZ2Ugc3RhdHVzLCBldGMuKSwgY2FyZWVyIGluZm9ybWF0aW9uIChqb2Igcm9sZSwgam9iIGludm9sdmVtZW50LCBkZXBhcnRtZW50LCB3b3JraW5nIHllYXJzLCBzYWxhcnksIGV0Yy4pLCBqb2Igc2F0aXNmYWN0aW9uIG1lYXN1cmUgKHdvcmstbGlmZSBiYWxhbmNlLCBqb2IvcmVsYXRpb25zaGlwL2Vudmlyb25tZW50IHNhdGlzZmFjdGlvbiksIHBlcmZvcm1hbmNlIHJhdGluZywgYW5kIG90aGVyIG1pc2NlbGxhbmVvdXMgaW5mb3JtYXRpb24uIFVuZm9ydHVuYXRlbHksIHRoZXJlIGlzIG5vIHN1Y2ggdmFyaWFibGUgdGhhdCBpbmZvcm1zIGlmIHRoZSBhdHRyaXRpb24gaXMgdm9sdW50YXJ5IG9yIGludm9sdW50YXJ5LiBIb3dldmVyLCB3ZSBjb3VsZCBzdGlsbCBnYXRoZXIgYSBnb29kIGFtb3VudCBvZiBpbmZvcm1hdGlvbiBhbmQgZXhwbG9yZSB3aGF0IGFyZSB0aGUgcG90ZW50aWFsIGZhY3RvcnMgYmVoaW5kIGF0dHJpdGlvbi4gR2l2ZW4gdGhhdCB0aGlzIGlzIGEgZmljdGlvbmFsIGRhdGFzZXQgcmVmZXJyaW5nIHRvIG5vIHNwZWNpZmljIGNvbXBhbmllcywgd2Ugd2lsbCBub3QgbWFrZSBhbnkganVkZ2VtZW50cyBvbiB3aGV0aGVyIG9uZSBzdGF0aXN0aWNzIGlzIHRvbyBoaWdoIG9yIG9uZSBhc3BlY3QgaXMgYWJub3JtYWw7IHdlIHNpbXBseSBhaW0gdG8gZXhwbG9yZSBwb3RlbnRpYWwgY2F1c2VzIGFuZCBjb3JyZWxhdGlvbiB3aXRoIGF0dHJpdGlvbiBzdGF0dXMuDQoNCmBgYHtyIERhdGF9DQpFbXBsb3llZSA8LSByZWFkX2NzdigiRW1wbG95ZWUuY3N2IikNCmBgYA0KDQojIEFuYWx5c2lzDQoNCiMjIDEuIEVtcGxveWVlIERlbW9ncmFwaGljcw0KDQojIyMgQWdlDQoNCj5XZSBmaXJzdCB3aXNoIHRvIGV4cGxvcmUgdGhlIGFnZSBkaXN0cmlidXRpb24gb2YgZW1wbG95ZWVzLCBhbmQgaW4gcGFydGljdWxhciwgdGhlIGFnZSBkaWZmZXJlbnRpYWwgYmV0d2VlbiB0aG9zZSB3aG8gaGF2ZSBsZWZ0IHRoZSBqb2IgYW5kIHRob3NlIHdobyBoYXZlbid0Lg0KDQpgYGB7cixmaWcuYWx0PSJBZ2UgZGlzdHJpYnV0aW9uIG9mIGVtcGxveWVlcy4gQ29tYmluYXRpb24gb2YgdGhyZWUgcGxvdHM6IHRoZSBwbG90IG9mIHRoZSBsZWZ0IGluY2x1ZGVzIGFsbCBlbXBsb3llZXMsIHRoZSBwbG90IG9uIHRoZSB0b3AgcmlnaHQgaW5jbHVkZXMgdGhvc2Ugd2l0aCBhdHRyaXRpb249WUVTLCB0aGUgcGxvdCBvbiB0aGUgYm90dG9tIHJpZ2h0IGluY2x1ZGVzIHRob3NlIHdpdGggYXR0cml0aW9uPU5PIn0NCmF0IDwtIEVtcGxveWVlICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBBZ2UpKSArDQogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICAgICAgICAgZmlsbCA9ICJncmF5NjUiKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGxhYnModGl0bGUgPSAiQWxsIGVtcGxveWVlcyIsIHkgPSAiIikNCg0KYXR5PC1FbXBsb3llZSAlPiUNCiAgZmlsdGVyKEF0dHJpdGlvbj09IlllcyIpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9QWdlKSkrDQogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICAgICAgICAgZmlsbCA9ICJicm93bjQiKSsNCiAgdGhlbWVfY2xhc3NpYygpKw0KICBsYWJzKHRpdGxlPSJBdHRyaXRlZCIseT0iIix4PSIiKQ0KDQphdG48LUVtcGxveWVlICU+JQ0KICBmaWx0ZXIoQXR0cml0aW9uPT0iTm8iKSAlPiUNCiAgZ2dwbG90KGFlcyh4PUFnZSkpKw0KICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgICAgICAgIGZpbGwgPSAiZG9kZ2VyYmx1ZTQiKSsNCiAgdGhlbWVfY2xhc3NpYygpKw0KICBsYWJzKHRpdGxlPSJOb24tYXR0cml0ZWQiLHk9IiIpDQoNCmF0ICsgKGF0eS9hdG4pICArIA0KICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiQWdlIGRpc3RyaWJ1dGlvbiBvZiBlbXBsb3llZXMiKSANCmBgYA0KDQo+QXMgc2hvd24gYWJvdmUsIHRoZSBhZ2UgcmFuZ2Ugb2YgZW1wbG95ZWVzIHNwYW5zIHdpZGVseSwgYWxsIHRoZSB3YXkgZnJvbSAxOCB0byA2MCB5ZWFycyBvbGQsIGFuZCB0aGUgZGlzdHJpYnV0aW9uIGlzIHJvdWdobHkgYmVsbCBzaGFwZWQgYnV0IHNvbWV3aGF0IHJpZ2h0LXNrZXdlZCwgd2l0aCB0aG9zZSB3aG8gYWdlIGJldHdlZW4gMjUtNDAgYmVpbmcgdGhlIG1ham9yIHdvcmtmb3JjZS4gT3ZlcmFsbCwgd2Ugc2VlIHRoYXQgdGhvc2Ugd2hvIGhhdmUgbGVmdCB0aGUgY29tcGFueSB0ZW5kIHRvIGJlIHlvdW5nZXIgdGhhbiB0aG9zZSB3aG8gaGF2ZW4ndCB3aXRoIG1vcmUgbGVmdC1za2V3bmVzcyBpbiB0aGUgYWdlIGRpc3RyaWJ1dGlvbiwgd2hpY2ggaXMgdG8gYmUgZXhwZWN0ZWQgYXMgeW91bmdlciBwZW9wbGUgd2l0aCBmZXdlciB3b3JrIGV4cGVyaWVuY2VzIHRlbmQgdG8gc2VlayBtb3JlIHBvdGVudGlhbHMgYnkgc3dpdGNoaW5nIGpvYnMsIHRob3VnaCB3ZSBmaW5kIHRoYXQgc3VjaCBkaWZmZXJlbmNlIGlzbid0IHF1aXRlIGxhcmdlLiBJbiBhZGRpdGlvbiwgd2UgYWxzbyBmaW5kIG5vdGljZWFibGUgc3Bpa2VzIGluIGFnZSB3aXRoIHJvdWdobHkgc2ltaWxhciBpbnRlcnZhbHMgaW4gYmV0d2Vlbi4gR2l2ZW4gdGhlIGRhdGEgc2FtcGxlIHNpemUgaXNuJ3QgcXVpdGUgc21hbGwsIHdlIGNhbiBzdXNwZWN0IHRoYXQgdGhlcmUgbWlnaHQgYmUgY2VydGFpbiByZWNydWl0bWVudCByZWFzb25zIG9uIHRoZSBjb21wYW5pZXMgc2lkZSBvdGhlciB0aGFuIHRvdGFsIHJhbmRvbW5lc3MuIE9uZSBwb3NzaWJsZSByZWFzb24gaXMgdGhhdCB0aGUgY29tcGFueSBtaWdodCBiZSBhY3RpdmVseSBzZWVraW5nIGNvbGxlZ2UgZ3JhZHVhdGVzIGV2ZXJ5IG90aGVyIHllYXIsIHdoaWNoIG1pZ2h0IGV4cGxhaW4gdGhlIHJvdWdobHkgc2ltaWxhcmx5LXNwYWNlZCBzcGlrZXMuDQoNCmBgYHtyLGV2YWw9RkFMU0UsIGZpZy5hbHQ9IkNvbXBhcmlzaW9uIG9mIEF0dHJpdGVkIGFuZCBOb3QgQXR0cml0ZWQgRW1wbG95ZWUgTnVtYmVyIGJ5IERlcGFydG1lbnQgb3ZlciBBZ2UifQ0KbmV3RW1wbG95ZWUgPC0gRW1wbG95ZWUgJT4lDQogIGdyb3VwX2J5KERlcGFydG1lbnQsIEFnZSkgJT4lDQogIHN1bW1hcmlzZShhdHRyaXRlZCA9IHN1bShBdHRyaXRpb24gPT0gIlllcyIpLA0KICAgICAgICAgICAgbm90QXR0cml0ZWQgPSBzdW0oQXR0cml0aW9uID09ICJObyIpKSAlPiUNCiAgbXV0YXRlKG5ld0RlcGFydG1lbnQgPSBpZmVsc2UoDQogICAgRGVwYXJ0bWVudCA9PSAiU2FsZXMiLA0KICAgICJBdHRyaXRlZCBTYWxlcyIsDQogICAgaWZlbHNlKA0KICAgICAgRGVwYXJ0bWVudCA9PSAiSHVtYW4gUmVzb3VyY2VzIiwNCiAgICAgICJBdHRyaXRlZCBIdW1hbiBSZXNvdXJjZXMiLA0KICAgICAgaWZlbHNlKA0KICAgICAgICBEZXBhcnRtZW50ID09ICJSZXNlYXJjaCAmIERldmVsb3BtZW50IiwNCiAgICAgICAgIkF0dHJpdGVkIFJlc2VhcmNoICYgRGV2ZWxvcG1lbnQiLA0KICAgICAgICAiTkEiDQogICAgICApDQogICAgKQ0KICApKQ0KbmV3RW1wbG95ZWUgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0gQWdlLCB5ID0gYXR0cml0ZWQsIGNvbG9yID0gRGVwYXJ0bWVudCksDQogICAgICAgICAgICBzaXplID0gMSwNCiAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0gQWdlLCB5ID0gbm90QXR0cml0ZWQsIGNvbG9yID0gRGVwYXJ0bWVudCksIHNpemUgPSAxKSArDQogIGdlb21fdGV4dChhZXMoDQogICAgeCA9IEFnZSwNCiAgICB5ID0gbm90QXR0cml0ZWQsDQogICAgbGFiZWwgPSBEZXBhcnRtZW50LA0KICAgIGNvbG9yID0gRGVwYXJ0bWVudA0KICApKSArDQogIGdlb21fdGV4dChhZXMoDQogICAgeCA9IEFnZSwNCiAgICB5ID0gYXR0cml0ZWQsDQogICAgbGFiZWwgPSBuZXdEZXBhcnRtZW50LA0KICAgIGNvbG9yID0gbmV3RGVwYXJ0bWVudA0KICApKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ29tcGFyaXNpb24gb2YgQXR0cml0ZWQgYW5kIE5vdCBBdHRyaXRlZCBFbXBsb3llZSBOdW1iZXIgYnkgRGVwYXJ0bWVudCBvdmVyIEFnZSIsDQogICAgc3VidGl0bGUgPSAiQWdlOiB7ZnJhbWVfYWxvbmd9IiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICIiDQogICkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwoDQogICAgdmFsdWVzID0gYygNCiAgICAgICJTYWxlcyIgPSAiYnJvd240IiwNCiAgICAgICJBdHRyaXRlZCBTYWxlcyIgPSAiYnJvd240IiwNCiAgICAgICJIdW1hbiBSZXNvdXJjZXMiID0gImRlZXBza3libHVlNCIsDQogICAgICAiQXR0cml0ZWQgSHVtYW4gUmVzb3VyY2VzIiA9ICJkZWVwc2t5Ymx1ZTQiLA0KICAgICAgIlJlc2VhcmNoICYgRGV2ZWxvcG1lbnQiID0gImdyYXk2NSIsDQogICAgICAiQXR0cml0ZWQgUmVzZWFyY2ggJiBEZXZlbG9wbWVudCIgPSAiZ3JheTY1Ig0KICAgICkNCiAgKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiMwMDZiYjMiLCBzaXplID0gMTAuNSxmYWNlID0gImJvbGQiLGhqdXN0ID0gMSksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICIjMDA2YmIzIikNCiAgKSArDQogIHRyYW5zaXRpb25fcmV2ZWFsKGFzLmludGVnZXIoQWdlKSkNCmBgYA0KDQpgYGB7ciwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0NCmFuaW1fc2F2ZSgiQ29tcGFyaXNpb24gb2YgQXR0cml0ZWQgYW5kIE5vdCBBdHRyaXRlZCBFbXBsb3llZSBOdW1iZXIgYnkgRGVwYXJ0bWVudCBvdmVyIEFnZS5naWYiKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkNvbXBhcmlzaW9uIG9mIEF0dHJpdGVkIGFuZCBOb3QgQXR0cml0ZWQgRW1wbG95ZWUgTnVtYmVyIGJ5IERlcGFydG1lbnQgb3ZlciBBZ2UuZ2lmIikNCmBgYA0KDQo+Rm9sbG93aW5nIHRoZSBsaW5lLCBpdCBpcyBub3Qgc3VycHJpc2luZyB0aGF0IGl0IHNob3dzIGEgc2ltaWxhciBwYXR0ZXJuIHdoZW4gZGl2aWRpbmcgdGhlIGVtcGxveWVlcyBieSBkZXBhcnRtZW50cyBpbiBnZW5lcmFsLiBOZXZlcnRoZWxlc3MsIHRoZXJlIGFyZSBzb21lIGRpZmZlcmVuY2VzIGFtb25nIGRlcGFydG1lbnRzLiBGb3IgU2FsZXMsIGJvdGggbGluZXMgZm9yIGF0dHJpdGVkIGFuZCBub3QtYXR0cml0ZWQgZm9sbG93IHRoZSBzYW1lIHByb2dyZXNzaW9uIGFjcm9zcyBhZ2UsIGluZGljYXRpbmcgdGhhdCBhdHRyaXRpb24gbWFpbmx5IGZvbGxvd3MgdGhlIGNoYW5nZSBvZiBlbXBsb3llZSBzaXplIGluIHRoZSBjb21wYW55LiBUaG91Z2ggd2UgYXJlIHJlc3RyaWN0ZWQgdG8gdGhlIHNtYWxsIGRhdGEgc2l6ZSBmb3IgdGhlIGh1bWFuIHJlc291cmNlcyBkZXBhcnRtZW50LCB3ZSBjYW4gdGVsbCB0aGF0IGFnZSBpcyBhIG1vcmUgaW1wb3J0YW50IGZhY3RvciB0aGFuIGVtcGxveWVlIHNpemUgaW4gZGVzY3JpYmluZyBlbXBsb3llZSBhdHRyaXRpb24uIEZvciB0aGUgcmVzZWFyY2ggYW5kIGRldmVsb3BtZW50IGRlcGFydG1lbnQsIHdlIGNhbiBpbnNwZWN0IGluIHR3byBwYXJ0cy4gVGhlIGZpcnN0IHBhcnTigJMgYWdlIDE4IHRvIGFnZSBhcm91bmQgMzLigJMgYm90aCBsaW5lcyBwcm9ncmVzcyBpbiBhIHZlcnkgc2ltaWxhciB3YXkuIEluIGNvbnRyYXN0LCB0aGUgdHdvIGxpbmVzIHN0YXJ0IHRvIGRpdmVyZ2UgYXJvdW5kIGFnZSAzMjogbm9uLWF0dHJpdGlvbiBpbmNyZWFzZXMgYW5kIGRlY3JlYXNlcyB3aGlsZSBhdHRyaXRpb24gZGVjcmVhc2VzIGFuZCB0aGVuIHJlbWFpbnMgYXQgYSByZWxhdGl2ZWx5IHNtYWxsIHNpemUgb2YgcGVvcGxlLiBPbmUgcG9zc2libGUgZXhwbGFuYXRpb24gaXMgdGhhdCByZXNlYXJjaCBhbmQgZGV2ZWxvcG1lbnQgcmVxdWlyZXMgYSBsb3Qgb2YgcHJlLWVmZm9ydCBiZWZvcmUgYWN0dWFsbHkgZ2FpbmluZyBzb21lIHJlc3BvbnNlLiBNZWFuaW5nIHRoZSB0aW1lIGJlZm9yZSBpdCBpcyBqdXN0IHN1bmsgY29zdC4gVGh1cywgc29tZSBtaWdodCBwcmVmZXIgdG8gc3RvcCBsb3NzIGluIHRpbWUgYnkgc3RhcnRpbmcgYSBuZXcgY2FyZWVyIHdoZW4gdGhleSBzdGlsbCBoYXZlIGEgY2hhbmNlIHdoaWxlIHNvbWUgb3RoZXJzIHByZWZlciB0byBzdGF5IGluIHRoZSBmaWVsZC4NCg0KIyMjIEdlbmRlcg0KDQpgYGB7cixmaWcuYWx0PSJtb3NhaWMgcGxvdCBvZiBhdHRyaXRpb24oeSkgdnMgZ2VuZGVyKHgpIn0NCm1vc2FpY3Bsb3QoDQogIHRhYmxlKEVtcGxveWVlJEdlbmRlciwNCiAgICAgICAgRW1wbG95ZWUkQXR0cml0aW9uKSwNCiAgbWFpbiA9ICJBdHRyaXRpb24gdnMuIEdlbmRlciIsDQogIG9mZiA9IDMsDQogIGJvcmRlciA9ICJ3aGl0ZSIsDQogIGNvbG9yID0gMToyLA0KICBsYXMgPSAxLA0KICBjZXguYXhpcyAgPSAxDQopDQpgYGANCg0KPkluIGdlbmVyYWwsIHRoZSBlbXBsb3llZSBhdHRyaXRpb24gcmF0ZSBpcyBhYm91dCAxNiUsIGFuZCB3ZSBjYW5ub3QgZGlzY2VybiBhbiBvYnZpb3VzIGRpc3RpbmN0aW9uIG9mIGF0dHJpdGlvbiByYXRlIGJldHdlZW4gbWFsZSBhbmQgZmVtYWxlcy4gV2UgY2FuLCBob3dldmVyLCBub3RpY2UgdGhhdCB0aGUgY29tcGFueSBnZW5lcmFsbHkgZW1wbG95cyBtb3JlIG1hbGVzIHRoYW4gZmVtYWxlcy4gVG8gZ2V0IGEgc2Vuc2Ugb2YgZ2VuZGVyIGRpc3RyaWJ1dGlvbiBhY3Jvc3MgZGVwYXJ0bWVudHMsIHdlIGFsc28gZHJhdyB0aGUgbW9zYWljIHBsb3QgYmVsb3cuIFdlIGZpbmQgdGhhdCBtYWxlcyBoYXZlIHRoZSBoaWdoZXN0IHByb3BvcnRpb24gaW4gdGhlIEh1bWFuIFJlc291cmNlIGRlcGFydG1lbnQsIHRob3VnaCB0aGVyZSBpcyBhbHNvIGNvbnNpZGVyYWJsZSBkaXNwYXJpdHkgaW4gdGhlIG90aGVyIHR3byBkZXBhcnRtZW50cy4NCg0KYGBge3IsZmlnLmFsdD0ibW9zYWljIHBsb3Qgb2YgZGVwYXJ0bWVudCh4KSB2cyBnZW5kZXIoeSkifQ0KbW9zYWljcGxvdCgNCiAgdGFibGUoRW1wbG95ZWUkRGVwYXJ0bWVudCwNCiAgICAgICAgRW1wbG95ZWUkR2VuZGVyKSwNCiAgbWFpbiA9ICJEZXBhcnRtZW50IHZzLiBHZW5kZXIiLA0KICBvZmYgPSA0LA0KICBib3JkZXIgPSAid2hpdGUiLA0KICBjb2xvciA9IDE6MiwNCiAgbGFzID0gMSwNCiAgY2V4LmF4aXMgID0gMQ0KKQ0KYGBgDQoNCiMjIyBBdHRyaXRpb24gdnMuIHllYXJzIGF0IGNvbXBhbnkNCg0KPlRvIGdldCBhIHNlbnNlIG9mIHR5cGljYWxseSBob3cgbG9uZyBhbiBlbXBsb3llZSBzdGF5cyBpbiBhIGNvbXBhbnksIEkgZHJhdyBhIEthcGxhbi1NZWllciBzdXJ2aXZhbCBjdXJ2ZSBvZiBlbXBsb3llZXMsIGFzIHNob3duIGluIHRoZSBncmFwaCBiZWxvdy4NCg0KYGBge3IsZmlnLmFsdD0iS2FwbGFuLU1laWVyIHN1cnZpdmFsIGN1cnZlIGZvciBlbXBsb3llZSBzdGF5aW5nIHdpdGhpbiB0aGUgY29tcGFueS4geCBheGlzIHN0YW5kcyBmb3IgeWVhcnMgaW4gY29tcGFueSwgYW5kIHl4aXMgc3RhbmRzIGZvciB0aGUgcHJvYmFiaWxpdHkgdGhhdCB0aGUgZW1wbG95ZWUgc3RpbGwgc3RheXMgYXQgdGhlIGNvbXBhbnkifQ0KZXM8LUVtcGxveWVlJT4lDQogIG11dGF0ZShhdHRyaXRpb249aWZlbHNlKEF0dHJpdGlvbj09IllFUyIsMCwxKSkNCmttPC1zdXJ2Zml0KFN1cnYoWWVhcnNBdENvbXBhbnksYXR0cml0aW9uKX4xLGRhdGE9ZXMpDQpwbG90KGttLGNvbmYuaW50PUZBTFNFLG1haW49IkthcGxhbi1NZWllciBzdXJ2aXZhbCBjdXJ2ZSBvZiBFbXBsb3llZSIseGxhYj0iWWVhcnMgYXQgY29tcGFueSIseWxhYj0iTm9uLWF0dHJpdGlvbiBwcm9iYWJpbGl0eSIpDQpgYGANCg0KPlRoZSB4LWF4aXMgc3RhbmRzIGZvciB5ZWFycyBhdCBhIGNvbXBhbnkgZm9yIGFuIGluZGl2aWR1YWwsIGFuZCB0aGUgeS1heGlzIHN0YW5kcyBmb3IgdGhlIHByb3BvcnRpb24gb2YgZW1wbG95ZWVzIHRoYXQgc3RpbGwgc3RheXMgYXQgdGhlIGNvbXBhbnksIG9yIHRoZSAic3Vydml2YWwiIHJhdGUgb2YgZW1wbG95ZWVzLiBNYXRoZW1hdGljYWxseSwgd2UgY291bGQgcmVwcmVzZW50IGl0IGFzICRQKFN1cnZpdmFsKT0xLVAoe0F0dHJpdGlvbn0pJCAgRnJvbSB0aGUgY3VydmUsIHdlIGZpbmQgdGhhdCBhYm91dCBoYWxmIG9mIGFsbCBlbXBsb3llZXMgbGVhdmUgdGhlIGNvbXBhbnkgd2l0aGluIDUgeWVhcnMsIGFuZCBvbmx5IDIwJSBvZiBhbGwgZW1wbG95ZWVzIHdpbGwgc3RheSB3aXRoaW4gdGhlIGNvbXBhbnkgZm9yIHRlbiB5ZWFycy4NCg0KIyMgMi4gUmVsYXRpb25zaGlwIGJldHdlZW4gYXR0cml0aW9uIGFuZCBJbmNvbWUNCg0KPk9uZSBiaWcgZmFjdG9yIHRoYXQgYW4gZW1wbG95ZWUgcXVpdHMgdGhlIGNvbXBhbnkgaXMgdGhhdCB0aGV5IGFyZSBub3Qgc2F0aXNmaWVkIHdpdGggdGhlaXIgaW5jb21lIGFuZCBzZWVrIHRvIGZpbmQgb3RoZXIgam9icyB3aXRoIGhpZ2hlciBpbmNvbWUgcHJvc3BlY3RzLiBGb3IgdGhpcyByZWFzb24sIHdlIHdpc2ggdG8gZXhwbG9yZSB0aGUgb3ZlcmFsbCBpbmNvbWUgc3RhdHVzIG9mIGVtcGxveWVlcy4gTm90ZTogYXMgdGhlIEthZ2dsZSBkYXRhc2V0IGRpZCBub3QgcHJvdmlkZSB0aGUgY3VycmVuY3kgdW5pdCBmb3IgaW5jb21lLCB3ZSB3aWxsIGFsc28gbm90IGluY2x1ZGUgdW5pdHMgZm9yIGluY29tZSBpbiBvdXIgYW5hbHlzaXMuDQoNCmBgYHtyLCBmaWcuYWx0PSAiVGhlIG1vbnRobHkgaW5jb21lIGRpc3RyaWJ1dGlvbnMgaW4gdGhlIGRhdGFzZXQgdXNpbmcgYSBkZW5zaXR5IHBsb3Qgd2l0aCB0aGUgYnJvd24gbGluZSBzaG93aW5nIHRoZSBtZWFuIG1vbnRobHkgaW5jb21lIGZvciBhbGwgd29ya2VycyIgfQ0KIEVtcF9hdHQgPC0gRW1wbG95ZWUgJT4lIA0KICBncm91cF9ieShBdHRyaXRpb24pICU+JQ0KICBzdW1tYXJpemUoYXZlX2luY29tZV9hdHQgPSBtZWFuKE1vbnRobHlJbmNvbWUpKQ0KDQpFbXBsb3llZSAlPiUgDQogIGxlZnRfam9pbihFbXBfYXR0LCANCiAgICAgICAgICAgIGJ5ID0gIkF0dHJpdGlvbiIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBNb250aGx5SW5jb21lLCBjb2xvciA9IEF0dHJpdGlvbikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pLCBjb2xvciA9ICJ3aGl0ZSIsIGZpbGwgPSAiZ3JheTY1IiwgYmlucyA9IDQwKSArDQogIGZhY2V0X3dyYXAodmFycyhBdHRyaXRpb24pKSArIA0KICAjIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBhdmVfaW5jb21lX2F0dCksIGNvbG9yID0gIiM0RjJDMURGRiIsIHNpemUgPSAxLjUpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhPS41LCBmaWxsPSIjMDA2NzQ3RkYiKSArIA0KICBsYWJzKHRpdGxlID0gIk1vbnRobHkgSW5jb21lIERpc3RyaWJ1dGlvbnMgYW5kIEF0dHJpdGlvbiBTaXR1YXRpb24iLCANCiAgICAgICBzdWJ0aXRsZSA9ICJEZW5zaXR5IFBsb3QiLA0KICAgICAgIHggPSBOVUxMLA0KICAgICAgIHkgPSBOVUxMKSArIA0KIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKQ0KDQogRW1wbG95ZWUgJT4lIA0KICBncm91cF9ieShBdHRyaXRpb24pICU+JQ0KICBzdW1tYXJpemUoYXZlX2luY29tZV9hdHQgPSBtZWFuKE1vbnRobHlJbmNvbWUpKSANCmBgYA0KDQo+VGhlIGFib3ZlIGhpc3RvZ3JhbSBkZXNjcmliZXMgdGhlIG92ZXJhbGwgaW5jb21lIGRpc3RyaWJ1dGlvbiBieSBhdHRyaXRpb24gc3RhdHVzLCB3aXRoIHRoZSBzbW9vdGhlZCBncmVlbiBkZW5zaXR5LiBPdmVyYWxsLCB3ZSBvYnNlcnZlIGEgZ29vZCBhbW91bnQgb2YgaW5jb21lIGRpc3Bhcml0eeKAk3RoZSBza2V3ZWQgZGlzdHJpYnV0aW9uIHNob3dzIHRoYXQgbW9zdCB3b3JrZXJzIHJlY2VpdmUgYSBtb250aGx5IGluY29tZSBsb3dlciB0aGFuIHRoZSBhdmVyYWdlLCB3aGlsZSBhIGZldyBwZW9wbGUgcmVjZWl2ZSBhIG1vbnRobHkgaW5jb21lIGZhciBoaWdoZXIgdGhhbiB0aGUgYXZlcmFnZSBpbmNvbWUgaW4gdGhpcyBjb21wYW55LiBJbiBhZGRpdGlvbiwgd2UgZmluZCB0aGF0IHRoZSBpbmNvbWUgZGlzcGFyaXR5IHNlZW1zIG1vcmUgZXh0cmVtZSB3aXRoaW4gdGhlIGF0dHJpdGVkIGVtcGxveWVlcyB3aXRoIG11Y2ggZ3JlYXRlciBza2V3bmVzcyBhbmQgZ3JlYXRlciBwZXJjZW50YWdlIGVhcm5pbmcgbGVzcyB0aGFuIDUsMDAwIGEgbW9udGgsIGFuZCB2ZXJ5IHNtYWxsIHBlcmNlbnRhZ2Ugb2YgZW1wbG95ZWVzIGVhcm5pbmcgb3ZlciAxMCwwMDAgbGVmdCB0aGUgY29tcGFueS4gVGhpcyBwcm92aWRlcyBjZXJ0YWluIGV2aWRlbmNlIHRoYXQgaW5jb21lIHByb3NwZWN0cyBhcmUgcXVpdGUgcmVsYXRlZCB3aXRoIGF0dHJpdGlvbiBzdGF0dXMuDQoNCmBgYHtyLCBmaWcuYWx0PSAiVGhlIG1vbnRobHkgaW5jb21lIGRpc3RyaWJ1dGlvbnMgYnkgdGhyZWUgZGVwYXJ0bWVudHMgYW5kIGdlbmRlciB1c2luZyBhIGJveCBwbG90IHdpdGggdGhlIGJsdWUgbGluZSBzaG93aW5nIHRoZSBtZWFuIG1vbnRobHkgaW5jb21lIGJ5IGRlcGFydG1lbnQiIH0NCkVtcGxveWVlX2RlcCA8LSBFbXBsb3llZSAlPiUNCiAgZ3JvdXBfYnkoRGVwYXJ0bWVudCkgJT4lDQogIHN1bW1hcml6ZShhdmVfaW5jb21lX2RlcCA9IG1lYW4oTW9udGhseUluY29tZSkpDQoNCiBFbXBsb3llZSAlPiUgDQogICBsZWZ0X2pvaW4oRW1wbG95ZWVfZGVwLA0KICAgICAgICAgICAgIGJ5PSAiRGVwYXJ0bWVudCIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBNb250aGx5SW5jb21lLCBjb2xvciA9IEF0dHJpdGlvbikpICsNCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC4yICkgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gYXZlX2luY29tZV9kZXApLCBjb2xvciA9ICIjNEYyQzFERkYiLCBzaXplID0gMSkgKw0KICBmYWNldF93cmFwKHZhcnMgKERlcGFydG1lbnQpKSArIA0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiWWVzIiA9ICJncmF5NjUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8iPSJicm93bjQiKSkgKyANCiAgbGFicyh0aXRsZSA9ICJNb250aGx5IEluY29tZSBEaXN0cmlidXRpb25zIGJ5IGRlcGFydG1lbnQgYW5kIEF0dHJpdGlvbiBTaXR1YXRpb24iLCANCiAgICAgICBzdWJ0aXRsZSA9ICJCb3ggUGxvdCIsDQogICAgICAgeCA9IE5VTEwsDQogICAgICAgeSA9IE5VTEwpDQpgYGANCg0KPldlIHRoZW4gdGFrZSBhIHN0ZXAgZnVydGhlciBpbnRvIHRoZSBtb250aGx5IGluY29tZSBkaXN0cmlidXRpb24gYnkgZGVwYXJ0bWVudCBhbmQgYXR0cml0aW9uIHN0YXR1cy4gVGhlIGJveHBsb3RzIGFib3ZlIHNob3cgdGhhdCwgYW1vbmcgdGhlIHRocmVlIGRlcGFydG1lbnRzLCBodW1hbiByZXNvdXJjZXMgYW5kIHJlc2VhcmNoICYgZGV2ZWxvcG1lbnQgZGVwYXJ0bWVudHMgdGVuZCB0byBoYXZlIGdyZWF0ZXIgaW5jb21lIGluZXF1YWxpdHkgYXMgd2Ugc2VlIHJlbGF0aXZlbHkgbGFyZ2VyIGdhcHMgYmV0d2VlbiB0aGUgbWVkaWFuIGFuZCB0aGUgYXZlcmFnZSBpbmNvbWUgKHNob3duIGJ5IHRoZSBkYXJrIGJyb3duIGxpbmUpLiBBdCB0aGUgc2FtZSB0aW1lLCBpdCBzZWVtcyB0aGF0IGluIHRoZXNlIHR3byBkZXBhcnRtZW50cywgbm9uLWF0dHJpdGVkIGVtcGxveWVlcyB0ZW5kIHRvIGhhdmUgbXVjaCBoaWdoZXIgbW9udGhseSBpbmNvbWUgdGhhbiB0aG9zZSB3aG8gbGVmdCB0aGUgY29tcGFueS4gSW5jb21lIGluZXF1YWxpdHkgYW5kIGF0dHJpdGlvbi9ub24tYXR0cml0aW9uIGRpZmZlcmVudGlhbCBpcyBsZXNzIGV4dHJlbWUgZm9yIHRoZSBzYWxlcyBkZXBhcnRtZW50LCBidXQgdGhlIGxvd2VyLWludGVycXVhcnRpbGUgZGlmZmVyZW5jZSBpcyBzdGlsbCBzdWJzdGFudGlhbC4gT3ZlcmFsbCwgdGhlIHNhbGVzIGRlcGFydG1lbnQgaGFzIHRoZSBoaWdoZXN0IGF2ZXJhZ2UgbW9udGhseSBpbmNvbWUgNjk1OS4yLCB0aGUgaHVtYW4gcmVzb3VyY2VzIGRlcGFydG1lbnQgaGFzIHRoZSBzZWNvbmQgaGlnaGVzdCBhdmVyYWdlIG1vbnRobHkgaW5jb21lIDY2NTQuNSwgYW5kIHRoZSByZXNlYXJjaCAmIGRldmVsb3BtZW50IGRlcGFydG1lbnQgaGFzIHRoZSBsb3dlc3QgYXZlcmFnZSBtb250aGx5IGluY29tZSA2MjgxLjMuDQoNCj5JbiBhZGRpdGlvbiB0byB0aGUgY3VycmVudCBpbmNvbWUgc3RhdHVzLCBwcm9iYWJseSBldmVuIG1vcmUsIGVtcGxveWVlcyBjYXJlIGFib3V0IGhvdyBsaWtlbHkgdGhlaXIgaW5jb21lIHdvdWxkIGluY3JlYXNlIGluIHRoZSBmdXR1cmUuIFdlIHRodXMgZHJhdyB0aGUgc2NhdHRlciBwbG90IGJlbG93IHRvIHNob3cgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGF2ZXJhZ2UgbW9udGhseSBpbmNvbWUgYW5kIHllYXJzIGF0IGNvbXBhbnkuIElmIHdlIGlnbm9yZSB0aGUgb3V0bGllcnMgd2hvIGxlZnQgdGhlIGNvbXBhbnkgYWZ0ZXIgb3ZlciAzMCB5ZWFycyBzZXJ2aW5nIGZvciB0aGUgY29tcGFueSwgd2UgZmluZCB0aGF0IHRoZSBwcm9zcGVjdCBvZiBwYXkgcmFpc2UgaXMgcm91Z2hseSB0aGUgc2FtZSBiZXR3ZWVuIHRob3NlIGJvdGggYXR0cml0aW9uIGdyb3VwcywgYXMgd2Ugc2VlIGEgcm91Z2hseSBwYXJhbGxlbCB0cmVuZC4NCg0KYGBge3IsIGZpZy5hbHQ9IkF2ZXJhZ2UgbW9udGhseSBpbmNvbWUgdnMuIFllYXJzIGF0IGNvbXBhbnkgIn0NCkVtcGxveWVlICU+JQ0KICBncm91cF9ieShEZXBhcnRtZW50LFllYXJzQXRDb21wYW55LEF0dHJpdGlvbikgJT4lDQogIHN1bW1hcml6ZShgQXZlcmFnZSBpbmNvbWVgID0gbWVhbihNb250aGx5SW5jb21lKSkgJT4lDQogIGdncGxvdChhZXMoeD1ZZWFyc0F0Q29tcGFueSkpICsNCiAgZ2VvbV9wb2ludChzaXplPTEsDQogICAgICAgICAgICBhZXMoIHk9YEF2ZXJhZ2UgaW5jb21lYCwNCiAgICAgICAgICAgIGNvbG9yPUF0dHJpdGlvbikpKw0KICBnZW9tX3Ntb290aChhZXMoeT1gQXZlcmFnZSBpbmNvbWVgLA0KICAgICAgICAgICAgIGNvbG9yPUF0dHJpdGlvbiksDQogICAgICAgICAgICAgc2UgPSBGQUxTRSxzaXplPTAuNykrDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlllcyIgPSAiZ3JheTY1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vIj0iYnJvd240IikpKw0KIyAgZmFjZXRfd3JhcCh+RGVwYXJ0bWVudCkrDQogIHRoZW1lX2NsYXNzaWMoKSsNCiAgbGFicyh4PSdUb3RhbCB3b3JraW5nIHllYXJzJywNCiAgICAgICB0aXRsZSA9ICJBdmVyYWdlIG1vbnRobHkgaW5jb21lIHZzLiBZZWFycyBhdCBjb21wYW55ICIsDQogICAgICAgeT0iTW9udGhseSBpbmNvbWUiKQ0KYGBgDQoNCj5XZSBsb29rIG1vcmUgY2xvc2VseSBhdCB0aGUgcGVyY2VudCBzYWxhcnkgaGlrZSBieSBkZXBhcnRtZW50IGluIHRoZSBncm91cCBvZiBib3hwbG90cyBiZWxvdy4gVGhlIHJlc3VsdHMgY29ycm9ib3JhdGUgdGhlIHByZXZpb3VzIGdyYXBoLiBPdGhlciB0aGFuIHRoZSBodW1hbiByZXNvdXJjZXMgZGVwYXJ0bWVudCB3aGljaCBoYXZlIHRoZSBmZXdlc3QgZW1wbG95ZWVzLCBpbiBib3RoIFImRCBhbmQgU2FsZXMgZGVwYXJ0bWVudHMsIHRoZSBpbmNvbWUgcHJvc3BlY3RzIGZvciB0aG9zZSB3aG8gaGF2ZSBhbmQgaGF2ZW7igJl0IGxlZnQgdGhlIGNvbXBhbnkgaXMgYXBwcm94aW1hdGVseSB0aGUgc2FtZSwgd2l0aCB2ZXJ5IHNpbWlsYXIgbWVkaWFuLCBtZWFuLCBhbmQgaW50ZXJxdWFydGlsZSBzYWxhcnkgaGlrZSBwZXJjZW50YWdlLiBUaHVzLCBmcm9tIHRoaXMgZGF0YSwgd2UgZG9u4oCZdCB0aGluayBmdXR1cmUgaW5jb21lIHByb3NwZWN0cyBwbGF5IGFzIGh1Z2UgYSByb2xlIGluIGF0dHJpdGlvbiBzdGF0dXMgYXMgdGhlIGN1cnJlbnQgaW5jb21lLg0KDQpgYGB7ciwgZmlnLmFsdD0iUGVyY2VudCBTYWxhcnkgSGlrZSBieSBEZXBhcnRtZW50IGFuZCBBdHRyaXRpb24ifQ0KRW1wbG95ZWUgJT4lDQogIGdncGxvdChhZXMoeT1QZXJjZW50U2FsYXJ5SGlrZSx4PUF0dHJpdGlvbiwgY29sb3I9QXR0cml0aW9uKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjIgKSsNCiAgZmFjZXRfd3JhcCh+RGVwYXJ0bWVudCkrDQogICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiWWVzIiA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJObyI9ImJyb3duNCIpKSsNCiAgdGhlbWVfY2xhc3NpYygpKw0KICBsYWJzKHRpdGxlID0gIlBlcmNlbnQgU2FsYXJ5IEhpa2UgYnkgRGVwYXJ0bWVudCBhbmQgQXR0cml0aW9uIix5PSIiKQ0KYGBgDQoNCiMjIDMuIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIEpvYiBTYXRpc2ZhY3Rpb24gYW5kIEF0dHJpdGlvbg0KDQo+UHJvYmFibHkgZXZlbiBtb3JlIGltcG9ydGFudCB0aGFuIGluY29tZSwgZW1wbG95ZWVz4oCZIG92ZXJhbGwgam9iIHNhdGlzZmFjdGlvbiByYXRpbmdzIGNvdWxkIHBvdGVudGlhbGx5IHRlbGwgbW9yZSBhYm91dCB3aGV0aGVyIHRoZXkgYXJlIGhhcHB5IHdpdGggdGhlaXIgam9iLiBXZSB0aHVzIGFsc28gd2lzaCB0byBleHBsb3JlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhdHRyaXRpb24gYW5kIGpvYiBzYXRpc2ZhY3Rpb24uIEluIG91ciBkYXRhc2V0LCBqb2IgcmF0aW5nIGhhcyBmb3VyIGxldmVsczogMSBtZWFuaW5nIOKAnGxvdyzigJ0gMiBtZWFuaW5nIOKAnG1lZGl1bSzigJ0gMyBtZWFuaW5nIOKAnGhpZ2gs4oCdIDQgbWVhbmluZyDigJx2ZXJ5IGhpZ2gu4oCdDQoNCmBgYHtyLCBmaWcuYWx0PSJKb2IgU2F0aXNmYWN0aW9uIGJ5IERlcGFydG1lbnQgQW5kIEF0dHJpdGlvbiBTdGF0dXMifQ0KbmV3RW1wbG95ZWVBdHRyaXRpb24gPC0gRW1wbG95ZWUgJT4lDQogIGdyb3VwX2J5KERlcGFydG1lbnQsSm9iU2F0aXNmYWN0aW9uLEF0dHJpdGlvbikgJT4lDQogIHN1bW1hcmlzZShudW1iZXIgPSBuKCkpDQoNCm5ld0VtcGxveWVlQXR0cml0aW9uUGxvdDwtIG5ld0VtcGxveWVlQXR0cml0aW9uICAlPiUgDQogIGdncGxvdChhZXMoeCA9IEpvYlNhdGlzZmFjdGlvbiwgeSA9IG51bWJlcix0ZXh0ID0gcGFzdGUoJ051bWJlciBvZiBQZW9wbGUgOicsIG51bWJlcikpICkrDQogIGdlb21fY29sKGFlcyggZmlsbCA9IEF0dHJpdGlvbikpICsNCiAgZmFjZXRfZ3JpZCgufkRlcGFydG1lbnQpKw0KICBsYWJzKHRpdGxlID0gIkpvYiBTYXRpc2ZhY3Rpb24gYnkgRGVwYXJ0bWVudCBBbmQgQXR0cml0aW9uIFN0YXR1cyIsDQogICAgICAgeCA9IE5VTEwsDQogICAgICAgeSA9IE5VTEwsDQogICAgICAgZmlsbD1OVUxMKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKA0KICAgIHZhbHVlcyA9IGMoImZpcmVicmljazMiLCAiYmxhY2siKSwNCiAgICBsYWJlbHMgPSBjKCJOb3QgQXR0cml0ZWQiLCAiQXR0cml0ZWQiKQ0KICApICsNCiB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDExKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjEsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMiksDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoDQogICAgICBmYWNlID0gImJvbGQiLA0KICAgICAgaGp1c3QgPSAyLA0KICAgICAgdmp1c3QgPSAyDQogICAgKQ0KICApDQoNCg0KYGBgDQoNCmBgYHtyLCBmaWcuYWx0PSJKb2IgU2F0aXNmYWN0aW9uIGJ5IERlcGFydG1lbnQgQW5kIEF0dHJpdGlvbiBTdGF0dXMifQ0KZ2dwbG90bHkobmV3RW1wbG95ZWVBdHRyaXRpb25QbG90LCB0b29sdGlwID0gYygidGV4dCIpICkNCmBgYA0KDQo+V2hlbiBsb29raW5nIGF0IGpvYiBzYXRpc2ZhY3Rpb24sIGl0IGlzIHVuc3VycHJpc2luZyB0aGF0IHRoZSBlbXBsb3llZXMgd2hvIHJhdGVkIOKAnDHigJ0gd291bGQgbW9yZSB0ZW5kIHRvIGxlYXZlIHRoZSBjb21wYW55IGluIGdlbmVyYWwuIEluIGFkZGl0aW9uLCBmb3IgdGhlIGh1bWFuIHJlc291cmNlcyBkZXBhcnRtZW50LCBoYWxmIG9mIHRoZSBlbXBsb3llZXMgcmF0ZWQg4oCcMeKAnSBhdHRyaXRlZC4gSG93ZXZlciwgaXQgaXMgaW50ZXJlc3RpbmcgdG8gbm90ZSB0aGF0IHRoZXJlIGFyZSBldmVuIGxlc3MgZW1wbG95ZWVzIGF0dHJpdGVkIHdpdGggcmF0aW5nIOKAnDLigJ0gdGhhbiBvdGhlciB0d28gaGlnaGVyIHJhdGluZ3MuIE1vcmVvdmVyLCBmb3IgdGhlIG90aGVyIHR3byBkZXBhcnRtZW50cywgYWx0aG91Z2ggdGhlIGF0dHJpdGlvbiBkZWNyZWFzZXMgd2l0aCB0aGUgaW5jcmVhc2Ugb2YgcmF0aW5nLCB0aGUgYXR0cml0aW9uIGRpZmZlcmVuY2VzIGFtb25nIGRpZmZlcmVudCByYXRpbmdzIGFyZSBub3QgZXhwbGljaXQuIFRodXMsIGpvYiBzYXRpc2ZhY3Rpb24gbWlnaHQgbm90IGJlIGEgdmVyeSBpbmZvcm1hdGl2ZSBpbmZsdWVuY2Ugd2hlbiBldmFsdWF0aW5nIHRoZSBhdHRyaXRpb24uIFNvbWUgcG9zc2libGUgZXhwbGFuYXRpb25zIG1pZ2h0IGJlIHRoYXQgZW1wbG95ZWVz4oCZIHJhdGluZyBtaWdodCB2YXJ5IG92ZXIgdGltZSBvciBzb21lIG1pZ2h0IG5vdCB0cmVhdCB0aGUgcmF0aW5nIHNlcmlvdXNseSBlbm91Z2ggdG8gcmVzcG9uZCB3aXRoIGEgdmFsaWQgdmFsdWUuDQoNCiNDb25jbHVzaW9uDQoNCj5FbXBsb3llZSBhdHRyaXRpb24gaXMgYW4gaW1wb3J0YW50IHBpZWNlIG9mIGluZm9ybWF0aW9uIHRvIGtlZXAgdHJhY2sgb2YgZm9yIGFueSBsYXJnZSBjb21wYW55LCBhcyBpdCBkZWVwbHkgY29uY2VybnMgZW1wbG95ZWVz4oCZIG1vcmFsZSwgd29yayBlbnZpcm9ubWVudCwgYW5kIHByb2R1Y3Rpb24gY29udGludWl0eSBvZiB0aGUgb3JnYW5pemF0aW9uLiBJbiBvdXIgS2FnZ2xlIGRhdGFzZXQsIG92ZXJhbGwsIHdlIGZpbmQgdGhhdCBlbXBsb3llZSBhdHRyaXRpb24gYXBwZWFycyB0byBoYXZlIHRoZSBncmVhdGVzdCBjb3JyZWxhdGlvbiB3aXRoIGluY29tZSBsZXZlbHMsIHdoaWxlIGZ1dHVyZSBpbmNvbWUgcHJvc3BlY3RzIGFuZCBqb2Igc2F0aXNmYWN0aW9uIHJhdGluZ3Mgc2VlbSBsZXNzIGltcG9ydGFudCBmYWN0b3JzLiBUaGlzIGhhcyBiZWVuIGluZm9ybWF0aXZlIGZvciB1cyBhbmQgZXNwZWNpYWxseSBmb3IgaHVtYW4gcmVzb3VyY2VzIHRvIHVuZGVyc3RhbmQgdGhlIGdlbmVyYWwgdHJlbmQgYW5kIGV4cGxhbmF0b3J5IGZhY3RvcnMgb2YgZW1wbG95ZWUgYXR0cml0aW9uLiANCg0KPkhvd2V2ZXIsIHdlIGFsc28gYWRtaXR0ZWRseSBmYWNlIGxpbWl0YXRpb25zIHdpdGggb3VyIGRhdGFzZXQuIEZpcnN0LCB3aGlsZSB3ZSBhcHByZWNpYXRlIHRoYXQgdGhlIGZpY3Rpb25hbCBkYXRhc2V0IHByb3RlY3RzIGluZGl2aWR1YWwgcHJpdmFjeSwgYXMgd2UgY2Fubm90IGlkZW50aWZ5IGFueSBzcGVjaWZpYyBjb21wYW55LCB3ZSBkb27igJl0IGtub3cgaG93IHR5cGljYWwgb3VyIGRhdGEgaXMgYW5kIGlmIHRoZSBkYXRhIGNhbiB3ZWxsIHJlcHJlc2VudCBhbGwgc2ltaWxhciBiaW9tZWRpY2FsIGNvbXBhbmllcy4gU2Vjb25kLCBzaW5jZSB3ZSBjYW5ub3QgdHJhY2sgd2hldGhlciBhdHRyaXRpb24gaXMgdm9sdW50YXJ5IG9yIG5vdCwgd2UgZmFjZSByZXN0cmljdGlvbnMgaW4gZHJhd2luZyBtb3JlIG1lYW5pbmdmdWwgY29uY2x1c2lvbnMgZnJvbSBvdXIgZGF0YS4gSWYgd2Ugd2VyZSBhYmxlIHRvIGxvY2F0ZSB0aGUgZGF0YSBtb3JlIHNwZWNpZmljYWxseSBhdCB2b2x1bnRhcnkgYXR0cml0aW9uLCB3ZSBtaWdodCBiZSBhYmxlIHRvIG1vcmUgY2xvc2VseSBpZGVudGlmeSBwb3RlbnRpYWwgcmVhc29ucyBmcm9tIHRoZSBjb21wYW5pZXPigJkgc2lkZSBmb3IgZW1wbG95ZWVzIHF1aXR0aW5nLiBGaW5hbGx5LCBnaXZlbiB0aGF0IG91ciBkYXRhc2V0LCB3aGlsZSByZWFzb25hYmx5IGxhcmdlIGVub3VnaCBmb3IgdXMgdG8gbWFrZSB2aXN1YWwgcmVwcmVzZW50YXRpb25zLCBkb2VzIG5vdCBjb250YWluIHF1aXRlIG1hbnkgYXR0cml0ZWQgZGF0YSBwb2ludHMoYWJvdXQgb3ZlciAyMDApLCBhbmQgY29udGFpbnMgb25seSB0aHJlZSBkZXBhcnRtZW50cyAoU2FsZXMsIFImRCwgSHVtYW4gcmVzb3VyY2VzKSwgd2UgY291bGRu4oCZdCByZWFzb25hYmx5IGluY2x1ZGUgYWxsIG9yIGFzIG1hbnkgdmFyaWFibGVzIGFzIHdlIGRlc2lyZSwgYXMgdGhhdCB3b3VsZCBsZWF2ZSB0b28gZmV3IGRhdGEgcG9pbnRzIGluIGVhY2ggZ3JvdXAuIA0KDQo=